//
//  TSCMySidebar.m
//  Tsc_IOS
//
//  Created by Rio on 15-5-12.
//  Copyright (c) 2015年 idream. All rights reserved.
//

#import "TSCMySidebar.h"
#import "TSCSDK.h"

#define TSC_SIDEBAR_DIALOG_CT_DIC_KEY_WIDTH @"width"
#define TSC_SIDEBAR_DIALOG_CT_DIC_KEY_HEIGHT @"height"
#define TSC_SIDEBAR_DIALOG_CT_DIC_KEY_CENTER_X @"centerX"
#define TSC_SIDEBAR_DIALOG_CT_DIC_KEY_CENTER_Y @"centerY"
#define TSC_SIDEBAR_DIALOG_CT_DIC_KEY_TOP @"top"
#define TSC_SIDEBAR_DIALOG_CT_DIC_KEY_LFET @"left"
#define TSC_SIDEBAR_DIALOG_CT_DIC_KEY_BOTTOM @"bottom"
#define TSC_SIDEBAR_DIALOG_CT_DIC_KEY_RIGHT @"right"

@implementation TSCMySidebar {
    UIView * _viBG; // 背景
    UIView * _viDialog; // 居中的窗口
    
    NSDictionary * _dialogCtDic; // 保存dialog的所有约束，方便同时激活，或者同时取消
    NSArray * _customViewCtArr; // 保存customView的所有约束，方便同时激活，或者同时取消
    
    BOOL _isAnimating; // 是否正在显示动画。如果正在显示动画，则不允许其他动画执行
}

#pragma mark init

- (id) init {
    self = [super init];
    if (self) {
        [self initSidebar];
    }
    return self;
}

- (void) initSidebar {
    
    // 1 初始化私有属性
    
    // 以下变量在首次显示时再初始化
    // _viBG
    // _viDialog
    // _ctViDialogDic
    
    _isAnimating = NO;
    
    // 2 初始化公有属性
    
    // _vcMain在调用者中初始化
    
    _presentStyle = TSCSidebarPresentStyleFlyFromBottom;
    _isPresenting = NO;
    _hasBGColor = NO;
    _hasRoundCorner = NO;
    _hasShadow = NO;
    _bgClickedDismissAnimated = YES;
    
    _dialogWType = TSCSidebarDialogWHTypePrefer;
    _dialogHType = TSCSidebarDialogWHTypePrefer;
    _dialogCustomViewSizePosition = TSCSideBarDialogCustomViewSizePositionFillParent;
}

#pragma mark public

- (void) presentAnimated:(BOOL)animated completion:(BSidebarCompletion)completion {
    
    NSAssert(_vcMain, @"[E]%s: 显示侧边栏时，_vcMain不能为nil！请先设置_vcMain！", __FUNCTION__);
    
    // 如果正在处理动画，或者已经显示了，直接返回
    if (_isAnimating || _isPresenting) {
        return;
    } else {
        _isAnimating = YES;
    }
    
    // 首次显示，先创建UI元素及约束
    // 注：为了保证属性变化能够及时反映在界面上，每次显示都重新创建界面，而不是仅在第一次显示就确定了各显示属性永远不变
    //    if (_viBG == nil) {
    [self constructUI];
    //    }
    
    // 显示UI
    [self presentUI:animated completion:completion presentStyle:_presentStyle];
    
}


- (void) dismissAnimated:(BOOL)animated completion:(BSidebarCompletion)completion {
    
    NSAssert(_vcMain, @"[E]%s: 隐藏侧边栏时，_vcMain不能为nil！请先设置_vcMain！", __FUNCTION__);
    
    // 如果正在处理动画，或者已经显示了，直接返回
    if (_isAnimating || _isPresenting == NO) {
        return;
    } else {
        _isAnimating = YES;
    }
    
    // 关闭UI
    [self dismissUI:animated completion:completion presentStyle:_presentStyle];
}

#pragma mark private

// 创建UI
- (void) constructUI {
    UIView * vcView = _vcMain.view;
    
    // 初始化背景
    _viBG = [[UIView alloc]init];
    if (_hasBGColor) {
        _viBG.backgroundColor = COLOR_MT_DIALOG_MODAL;
    }
    _viBG.hidden = NO; // 为了能使背景色逐渐显示，先将其隐藏
    [vcView addSubview:_viBG];
    
    _viBG.userInteractionEnabled = YES;
    [_viBG addGestureRecognizer:[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(viBGClicked)]];
    
    _viBG.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_viBG]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_viBG)]]; // 宽 == 屏宽
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_viBG]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_viBG)]]; // 高 == 屏高
    
    // 根据配置，计算居中窗口（dialog）的宽度约束、高度约束
    _viDialog = [[UIView alloc]init];
    NSLayoutConstraint * ctDialogW = nil;
    NSLayoutConstraint * ctDialogH = nil;
    NSLayoutConstraint * ctDialogTop = nil;
    NSLayoutConstraint * ctDialogLeft = nil;
    NSLayoutConstraint * ctDialogBottom = nil;
    NSLayoutConstraint * ctDialogRight = nil;
    switch (_dialogWType) {
        case TSCSidebarDialogWHTypeFillParent : {
            ctDialogW = [NSLayoutConstraint constraintWithItem:_viDialog attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:vcView attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f]; // 宽度 == 父view宽度
            break;
        }
        case TSCSidebarDialogWHTypePrefer : {
            ctDialogW = [NSLayoutConstraint constraintWithItem:_viDialog attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:(MIN(UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT) / 2)]; // 宽度 == 父view宽度、高度较小值的一半
            break;
        }
        case TSCSidebarDialogWHTypeFix : {
            // 必须设置宽度值
            NSAssert(_dialogW > 0, @"[E]%s: 构造侧边栏UI时，如果_dialogWType设置为TSCSidebarDialogWHTypeFix，则必须设置_dialogW的值大于0！", __FUNCTION__);
            
            ctDialogW = [NSLayoutConstraint constraintWithItem:_viDialog attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_dialogW]; // 宽度 == 固定的宽度值
            
            break;
        }
        case TSCSidebarDialogWHTypeDynamic : {
            // 必须设置自定义view，不然动态宽度没有依据
            NSAssert(_customView, @"[E]%s: 构造侧边栏UI时，如果_dialogWType设置为TSCSidebarDialogWHTypeDynamic，则必须设置_customView！", __FUNCTION__);
            
            // 自定义view的大小、位置类型，必须为填充父view
            NSAssert(_dialogCustomViewSizePosition == TSCSideBarDialogCustomViewSizePositionFillParent, @"[E]%s: 构造侧边栏UI时，如果_dialogWType设置为TSCSidebarDialogWHTypeDynamic，则_dialogCustomViewSizePosition的值必须是TSCSideBarDialogCustomViewSizePositionFillParent！", __FUNCTION__);
            
            // 动态宽度时，应设置left、right约束
            ctDialogLeft = [NSLayoutConstraint constraintWithItem:_viDialog attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:_customView attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]; // left == customView left
            ctDialogRight = [NSLayoutConstraint constraintWithItem:_viDialog attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:_customView attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]; // right == customView right
            
            break;
        }
        default: {
            NSAssert(YES == NO, @"[E]%s: 构造侧边栏UI时，传入了错误的_dialogWType！", __FUNCTION__);
            break;
        }
    }
    switch (_dialogHType) {
        case TSCSidebarDialogWHTypeFillParent : {
            ctDialogH = [NSLayoutConstraint constraintWithItem:_viDialog attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:vcView attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]; // 高度 == 父view高度
            break;
        }
        case TSCSidebarDialogWHTypePrefer : {
            ctDialogH = [NSLayoutConstraint constraintWithItem:_viDialog attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:(MAX(UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT) / 2)]; // 高度 == 父view宽度、高度较大值的一半
            break;
        }
        case TSCSidebarDialogWHTypeFix : {
            // 必须设置高度值
            NSAssert(_dialogH > 0, @"[E]%s: 构造侧边栏UI时，如果_dialogHType设置为TSCSidebarDialogWHTypeFix，则必须设置_dialogH的值大于0！", __FUNCTION__);
            
            ctDialogH = [NSLayoutConstraint constraintWithItem:_viDialog attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_dialogH]; // 高度 == 固定的高度值
            
            break;
        }
        case TSCSidebarDialogWHTypeDynamic : {
            // 必须设置自定义view，不然动态高度没有依据
            NSAssert(_customView, @"[E]%s: 构造侧边栏UI时，如果_dialogHType设置为TSCSidebarDialogWHTypeDynamic，则必须设置_customView！", __FUNCTION__);
            
            // 自定义view的大小、位置类型，必须为填充父view
            NSAssert(_dialogCustomViewSizePosition == TSCSideBarDialogCustomViewSizePositionFillParent, @"[E]%s: 构造侧边栏UI时，如果_dialogWType设置为TSCSidebarDialogWHTypeDynamic，则_dialogCustomViewSizePosition的值必须是TSCSideBarDialogCustomViewSizePositionFillParent！", __FUNCTION__);
            
            // 动态宽度时，应设置top、bottom约束
            ctDialogTop = [NSLayoutConstraint constraintWithItem:_viDialog attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_customView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; // top == customView top
            ctDialogBottom = [NSLayoutConstraint constraintWithItem:_viDialog attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_customView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; // bottom == customView bottom
            
            break;
        }
        default: {
            NSAssert(YES == NO, @"[E]%s: 构造侧边栏UI时，传入了错误的_dialogHType！", __FUNCTION__);
            break;
        }
    }
    
    _dialogCtDic = [NSDictionary dictionaryWithObjectsAndKeys:
                    // 宽
                    ctDialogW == nil ? [NSNull null] : ctDialogW,
                    TSC_SIDEBAR_DIALOG_CT_DIC_KEY_WIDTH,
                    // 高
                    ctDialogH == nil ? [NSNull null] : ctDialogH,
                    TSC_SIDEBAR_DIALOG_CT_DIC_KEY_HEIGHT,
                    // X轴居中
                    [NSLayoutConstraint constraintWithItem:_viDialog attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:vcView attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f],
                    TSC_SIDEBAR_DIALOG_CT_DIC_KEY_CENTER_X,
                    // Y轴居中
                    [NSLayoutConstraint constraintWithItem:_viDialog attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:vcView attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f],
                    TSC_SIDEBAR_DIALOG_CT_DIC_KEY_CENTER_Y,
                    // top
                    ctDialogTop == nil ? [NSNull null] : ctDialogTop,
                    TSC_SIDEBAR_DIALOG_CT_DIC_KEY_TOP,
                    // left
                    ctDialogLeft == nil ? [NSNull null] : ctDialogLeft,
                    TSC_SIDEBAR_DIALOG_CT_DIC_KEY_LFET,
                    // bottom
                    ctDialogBottom == nil ? [NSNull null] : ctDialogBottom,
                    TSC_SIDEBAR_DIALOG_CT_DIC_KEY_BOTTOM,
                    // right
                    ctDialogRight == nil ? [NSNull null] : ctDialogRight,
                    TSC_SIDEBAR_DIALOG_CT_DIC_KEY_RIGHT,
                    nil];
    
    // 初始化居中窗口（dialog）
    _viDialog.backgroundColor = _vcMain.view.backgroundColor; // 使dialog的背景色和主vc相同
    if (_hasRoundCorner) {
        [TSCMyUIUtil setUIRoundRectBG:_viDialog radius:10.0f];
    }
    if (_hasShadow) {
        [TSCMyUIUtil setUIShadow:_viDialog];
    }
    if (_hasBorder) {
        [TSCMyUIUtil setUIRoundBorder:_viDialog radius:0.0f borderColor:[UIColor lightGrayColor] borderWidth:1.0f];
    }
    [vcView addSubview:_viDialog];
    
    // 给居中窗口（dialog）添加自定义子view
    if (_customView) {
        [_viDialog addSubview:_customView];
        
        if (_dialogCustomViewSizePosition == TSCSideBarDialogCustomViewSizePositionFillParent) {
            
            NSMutableArray * customViewCtPositionArr = [NSMutableArray array]; // 位置约束
            NSMutableArray * customViewCtWArr = [NSMutableArray array]; // 宽度约束
            NSMutableArray * customViewCtHArr = [NSMutableArray array]; // 高度约束
            
            // 约束：位置
            [customViewCtPositionArr addObject:[NSLayoutConstraint constraintWithItem:_customView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_viDialog attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]]; // customView top == dialog top
            [customViewCtPositionArr addObject:[NSLayoutConstraint constraintWithItem:_customView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:_viDialog attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]]; //  customView left == dialog left
            
            // 约束：宽度
            // 和dialog保持一致
            if (_dialogWType != TSCSidebarDialogWHTypeDynamic) {
                [customViewCtWArr addObject:[NSLayoutConstraint constraintWithItem:_customView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_viDialog attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f]]; // customView width == dialog width
            }
            // 使用frame的width
            else if (_customView.frame.size.width > 0) {
                [customViewCtWArr addObject:[NSLayoutConstraint constraintWithItem:_customView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_customView.frame.size.width]]; // customView width == customView.frame.width
            }
            // 自行管理宽度
            else {
                // do nothing
            }
            
            // 约束：高度
            // 和dialog保持一致
            if (_dialogHType != TSCSidebarDialogWHTypeDynamic) {
                [customViewCtHArr addObject:[NSLayoutConstraint constraintWithItem:_customView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:_viDialog attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]]; // customView height == dialog height
            }
            // 使用frame的height
            else if (_customView.frame.size.height > 0) {
                [customViewCtHArr addObject:[NSLayoutConstraint constraintWithItem:_customView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_customView.frame.size.height]];
            }
            // 自行管理宽度
            else {
                // do nothing
            }
            
            _customViewCtArr = [[[NSArray arrayWithArray:customViewCtPositionArr] arrayByAddingObjectsFromArray:customViewCtWArr] arrayByAddingObjectsFromArray:customViewCtHArr];
        }
    }
    
    // 生效dialog、customView的约束
    // 注：除dialog两个center约束外，将所有dialog、customView的约束都生效，这样能保证dialog、customView立即获得最新的frame，即使两者从界面上看上去就是应用约束后的样子
    // 注：调用顺序很重要，一定要先激活约束，再layoutIfNeeded()
    [self enableDialogCtExceptCenter];
    if (_customView) {
        [self enableCustomViewCtAll];
    }
    [_viDialog layoutIfNeeded];
    if (_customView) {
        [_customView layoutIfNeeded];
    }
}

// （根据各种不同的显示风格）显示UI
// 注：该方法必须在constructUI()之后调用
- (void) presentUI:(BOOL)animated completion:(BSidebarCompletion)completion presentStyle:(TSCSidebarPresentStyle)presentStyle {
    
    // 1 显示触控背景
    _viBG.alpha = 0;
    _viBG.hidden = NO;
    [UIView animateWithDuration:CONFIG_ANIMATION_DURATION_QUICK_S animations:^{
        _viBG.alpha = 1;
    }];
    
    // 2 显示dialog
    // 2.1 飞入
    if (presentStyle == TSCSidebarPresentStyleFlyFromTop ||
        presentStyle == TSCSidebarPresentStyleFlyFromLeft ||
        presentStyle == TSCSidebarPresentStyleFlyFromBottom ||
        presentStyle == TSCSidebarPresentStyleFlyFromRight
        ) {
        
        // 计算移动前后的frame
        // 注：此时需保证dialog、customView的约束都生效了，且更新过dialog、customView的frame
        //        CGFloat dialogW = [self getDialogW:_dialogWType];
        //        CGFloat dialogH = [self getDialogH:_dialogHType];
        CGFloat dialogW = _viDialog.frame.size.width;
        CGFloat dialogH = _viDialog.frame.size.height;
        CGRect dialogFrame0 = [self getFlyFrame0:presentStyle dialogW:dialogW dialogH:dialogH];
        CGRect dialogFrame1 = [self getFlyFrame1:presentStyle dialogW:dialogW dialogH:dialogH];
        
        // 禁用所有约束，并设置初始frame
        [self disableDialogCtAll];
        _viDialog.frame = dialogFrame0;
        
        // 需要动画显示
        if (animated) {
            [UIView animateWithDuration:CONFIG_ANIMATION_DURATION_QUICK_S animations:^{
                _viDialog.frame = dialogFrame1;
            } completion:^(BOOL finished) {
                [self enableDialogCtAfterPresented];
                _isAnimating = NO;
                _isPresenting = YES;
                
                // 执行回调
                if (completion) {
                    completion();
                }
            }];
        }
        // 不用动画显示
        else {
            _viDialog.frame = dialogFrame1;
            
            [self enableDialogCtAfterPresented];
            _isAnimating = NO;
            _isPresenting = YES;
            
            // 执行回调
            if (completion) {
                completion();
            }
        }
    }
    // 2.2 淡入
    else if (presentStyle == TSCSidebarPresentStyleFadeIn) {
        [self enableDialogCtAfterPresented];
        
        // 需要动画显示
        if (animated) {
            _viDialog.alpha = 0;
            [UIView animateWithDuration:CONFIG_ANIMATION_DURATION_QUICK_S animations:^{
                _viDialog.alpha = 1.0f;
            } completion:^(BOOL finished) {
                _isAnimating = NO;
                _isPresenting = YES;
                
                // 执行回调
                if (completion) {
                    completion();
                }
            }];
        }
        // 不用动画显示
        else {
            _viDialog.alpha = 1.0f;
            _isAnimating = NO;
            _isPresenting = YES;
            
            // 执行回调
            if (completion) {
                completion();
            }
        }
    }
    else {
        NSAssert(YES == NO, @"侧边栏显示UI时，设置了暂不支持的_presentStyle！如果需要支持新的显示方式，请来这里补充代码！", __FUNCTION__);
    }
}

// （根据各种不同的显示风格）关闭UI
// 注：该方法必须在constructUI()之后调用
- (void) dismissUI:(BOOL)animated completion:(BSidebarCompletion)completion presentStyle:(TSCSidebarPresentStyle)presentStyle {
    
    // 1 隐藏触控背景
    [UIView animateWithDuration:CONFIG_ANIMATION_DURATION_QUICK_S animations:^{
        _viBG.alpha = 0;
    } completion:^(BOOL finished) {
        _viBG.hidden = YES;
    }];
    
    // 2 关闭dialog
    // 2.1 飞出
    if (presentStyle == TSCSidebarPresentStyleFlyFromTop ||
        presentStyle == TSCSidebarPresentStyleFlyFromLeft ||
        presentStyle == TSCSidebarPresentStyleFlyFromBottom ||
        presentStyle == TSCSidebarPresentStyleFlyFromRight
        ) {
        
        // 计算移动前后的frame
        // 注：此时需保证dialog、customView的约束都生效了，且更新过dialog、customView的frame
        //        CGFloat dialogW = [self getDialogW:_dialogWType];
        //        CGFloat dialogH = [self getDialogH:_dialogHType];
        CGFloat dialogW = _viDialog.frame.size.width;
        CGFloat dialogH = _viDialog.frame.size.height;
        // 注：因为是关闭，所以反向地调用了get方法
        CGRect dialogFrame0 = [self getFlyFrame1:presentStyle dialogW:dialogW dialogH:dialogH];
        CGRect dialogFrame1 = [self getFlyFrame0:presentStyle dialogW:dialogW dialogH:dialogH];
        
        // 禁用所有约束，并设置初始frame
        [self disableDialogCtAll];
        _viDialog.frame = dialogFrame0;
        
        // 需要动画显示
        if (animated) {
            [UIView animateWithDuration:CONFIG_ANIMATION_DURATION_QUICK_S animations:^{
                _viDialog.frame  = dialogFrame1;
            } completion:^(BOOL finished) {
                _viDialog.hidden = YES;
                _isAnimating = NO;
                _isPresenting = NO;
                [self disableDialogCtAll];
                if (_customView) {
                    [self disableCustomViewCtAll];
                }
                [_viBG removeFromSuperview];
                [_viDialog removeFromSuperview];
                
                
                // 执行回调
                if (completion) {
                    completion();
                }
            }];
        }
        // 不用动画显示
        else {
            _viDialog.frame  = dialogFrame1;
            
            _viDialog.hidden = YES;
            _isAnimating = NO;
            _isPresenting = NO;
            [self disableDialogCtAll];
            if (_customView) {
                [self disableCustomViewCtAll];
            }
            [_viBG removeFromSuperview];
            [_viDialog removeFromSuperview];
            
            // 执行回调
            if (completion) {
                completion();
            }
        }
    }
    // 2.2 淡出
    else if (presentStyle == TSCSidebarPresentStyleFadeIn) {
        
        // 需要动画显示
        if (animated) {
            [UIView animateWithDuration:CONFIG_ANIMATION_DURATION_QUICK_S animations:^{
                _viDialog.alpha = 0.0f;
            } completion:^(BOOL finished) {
                _isAnimating = NO;
                _isPresenting = NO;
                [self disableDialogCtAll];
                [self disableDialogCtAll];
                [_viBG removeFromSuperview];
                [_viDialog removeFromSuperview];
                
                // 执行回调
                if (completion) {
                    completion();
                }
            }];
        }
        // 不用动画显示
        else {
            _viDialog.alpha = 0.0f;
            _isAnimating = NO;
            _isPresenting = NO;
            [self disableDialogCtAll];
            [self disableDialogCtAll];
            [_viBG removeFromSuperview];
            [_viDialog removeFromSuperview];
            
            // 执行回调
            if (completion) {
                completion();
            }
        }
    }
    else {
        NSAssert(YES == NO, @"侧边栏显示UI时，设置了暂不支持的_presentStyle！如果需要支持新的显示方式，请来这里补充代码！", __FUNCTION__);
    }
    
}

//- (CGFloat) getDialogW:(TSCSidebarDialogWHType)dialogWType {
//    switch (dialogWType) {
//        case TSCSidebarDialogWHTypeFillParent : {
//            return UI_SCREEN_WIDTH; // 宽度 == 父view宽度
//            break;
//        }
//        case TSCSidebarDialogWHTypePrefer : {
//            return (MIN(UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT) / 2); // 宽度 == 父view宽度、高度较小值的一半
//            break;
//        }
//        case TSCSidebarDialogWHTypeFix : {
//            // 必须设置宽度值
//            NSAssert(_dialogW > 0, @"[E]%s: 计算侧边栏dialogW时，如果_dialogWType设置为TSCSidebarDialogWHTypeFix，则必须设置_dialogW的值大于0！", __FUNCTION__);
//
//            return _dialogW; // 宽度 == 固定的宽度值
//
//            break;
//        }
//        case TSCSidebarDialogWHTypeDynamic : {
//            // 必须设置自定义view，不然动态宽度没有依据
//            NSAssert(_customView, @"[E]%s: 计算侧边栏dialogW时，如果_dialogWType设置为TSCSidebarDialogWHTypeDynamic，则必须设置_customView！", __FUNCTION__);
//
//            //            BOOL isDialogTAMIC = _viDialog.translatesAutoresizingMaskIntoConstraints;
//            //            BOOL isCustomViewTAMIC = _customView.translatesAutoresizingMaskIntoConstraints;
//            //            if (isDialogTAMIC == YES) {
//            //                [self enableDialogCtExceptCenter];
//            //            }
//            //            if (isCustomViewTAMIC == YES) {
//            //                [self enableCustomViewCtAll];
//            //            }
//            // 注：应用约束时，不要判断translatesAutoresizingMaskIntoConstraints为YES再进行，而是一律进行，因为_customView是外部传来的引用，不会随MySidebar实例而销毁，所以_customView的translatesAutoresizingMaskIntoConstraints在第一次设置后，永远都是NO，除非手工设置为YES
//
//            [self enableDialogCtExceptCenter];
//            [self enableCustomViewCtAll];
//            [_viDialog layoutIfNeeded];
//            [_customView layoutIfNeeded];
//
//            // 动态计算得到的宽度不能小于0
//            NSAssert(_viDialog.frame.size.width > 0, @"[E]%s: 计算侧边栏dialogH时，如果_dialogWType设置为TSCSidebarDialogWHTypeDynamic，则必须保证_viDialog的width大于0！", __FUNCTION__);
//
//            // 动态宽度时，返回计算后dialog的宽度
//            return _viDialog.frame.size.width;
//
//            break;
//        }
//        default: {
//            NSAssert(YES == NO, @"[E]%s: 计算侧边栏dialogW时，传入了错误的_dialogWType！", __FUNCTION__);
//            break;
//        }
//    }
//}
//
//- (CGFloat) getDialogH:(TSCSidebarDialogWHType)dialogHType {
//    switch (dialogHType) {
//        case TSCSidebarDialogWHTypeFillParent : {
//            return UI_SCREEN_HEIGHT; // 高度 == 父view高度
//            break;
//        }
//        case TSCSidebarDialogWHTypePrefer : {
//            return (MAX(UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT) / 2); // 高度 == 父view宽度、高度较大值的一半
//            break;
//        }
//        case TSCSidebarDialogWHTypeFix : {
//            // 必须设置高度值
//            NSAssert(_dialogH > 0, @"[E]%s: 计算侧边栏dialogH时，如果_dialogWType设置为TSCSidebarDialogWHTypeFix，则必须设置_dialogH的值大于0！", __FUNCTION__);
//
//            return _dialogH; // 宽度 == 固定的宽度值
//
//            break;
//        }
//        case TSCSidebarDialogWHTypeDynamic :  {
//            // 必须设置自定义view，不然动态宽度没有依据
//            NSAssert(_customView, @"[E]%s: 计算侧边栏dialogH时，如果_dialogWType设置为TSCSidebarDialogWHTypeDynamic，则必须设置_customView！", __FUNCTION__);
//
//            //            BOOL isDialogTAMIC = _viDialog.translatesAutoresizingMaskIntoConstraints;
//            //            BOOL isCustomViewTAMIC = _customView.translatesAutoresizingMaskIntoConstraints;
//            //            if (isDialogTAMIC == YES) {
//            //                [self enableDialogCtExceptCenter];
//            //            }
//            //            if (isCustomViewTAMIC == YES) {
//            //                [self enableCustomViewCtAll];
//            //            }
//            // 注：应用约束时，不要判断translatesAutoresizingMaskIntoConstraints为YES再进行，而是一律进行，因为_customView是外部传来的引用，不会随MySidebar实例而销毁，所以_customView的translatesAutoresizingMaskIntoConstraints在第一次设置后，永远都是NO，除非手工设置为YES
//
//            [self enableDialogCtExceptCenter];
//            [self enableCustomViewCtAll];
//            [_viDialog layoutIfNeeded];
//            [_customView layoutIfNeeded];
//
//            // 动态计算得到的高度不能小于0
//            NSAssert(_viDialog.frame.size.height > 0, @"[E]%s: 计算侧边栏dialogH时，如果_dialogWType设置为TSCSidebarDialogWHTypeDynamic，则必须保证_viDialog的height大于0！", __FUNCTION__);
//
//            // 动态高度时，返回计算后dialog的高度
//            return _viDialog.frame.size.height;
//
//            break;
//        }
//        default: {
//            NSAssert(YES == NO, @"[E]%s: 计算侧边栏dialogH时，传入了错误的_dialogWType！", __FUNCTION__);
//            break;
//        }
//    }
//}


// 根据dialog显示风格（方向）获得移动前的frame
- (CGRect) getFlyFrame0:(TSCSidebarPresentStyle)presentStyle dialogW:(CGFloat)dialogW dialogH:(CGFloat)dialogH {
    switch (presentStyle) {
        case TSCSidebarPresentStyleFlyFromTop: {
            return CGRectMake(UI_SCREEN_WIDTH / 2 - dialogW / 2, 0 - dialogH, dialogW, dialogH);
            break;
        }
        case TSCSidebarPresentStyleFlyFromLeft: {
            return CGRectMake(0 - dialogW, UI_SCREEN_HEIGHT / 2 - dialogH / 2, dialogW, dialogH);
            break;
        }
        case TSCSidebarPresentStyleFlyFromBottom: {
            return CGRectMake(UI_SCREEN_WIDTH / 2 - dialogW / 2, UI_SCREEN_HEIGHT, dialogW, dialogH);
            break;
        }
        case TSCSidebarPresentStyleFlyFromRight: {
            return CGRectMake(UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT / 2 - dialogH / 2, dialogW, dialogH);
            break;
        }
            
        default: {
            NSAssert(YES == NO, @"[%s]: sidebar获得dialog显示前的frame时，_presentStyle设置了错误的值！调用此方法时，只能设置fly类型的值！", __FUNCTION__);
            return CGRectZero;
            break;
        }
    }
}

// 根据dialog显示风格（方向）获得移动后的frame
- (CGRect) getFlyFrame1:(TSCSidebarPresentStyle)presentStyle dialogW:(CGFloat)dialogW dialogH:(CGFloat)dialogH {
    switch (presentStyle) {
        case TSCSidebarPresentStyleFlyFromTop:
        case TSCSidebarPresentStyleFlyFromLeft:
        case TSCSidebarPresentStyleFlyFromBottom:
        case TSCSidebarPresentStyleFlyFromRight: {
            return CGRectMake(UI_SCREEN_WIDTH / 2 - dialogW / 2, UI_SCREEN_HEIGHT / 2 - dialogH / 2, dialogW, dialogH);
            break;
        }
        default: {
            NSAssert(YES == NO, @"[%s]: sidebar获得dialog显示后的frame时，_presentStyle设置了错误的值！调用此方法时，只能设置fly类型的值！", __FUNCTION__);
            return CGRectZero;
            break;
        }
    }
}

- (void) disableDialogCtAll {
    NSAssert(_dialogCtDic, @"[E]%s: 开启侧边栏dialog的约束时，约束dic不能为nil！", __FUNCTION__);
    
    _viDialog.translatesAutoresizingMaskIntoConstraints = YES;
    
    for (NSLayoutConstraint * ct in [_dialogCtDic allValues]) {
        // 注：ct可能为[NSNull null]
        if ([ct isKindOfClass:[NSLayoutConstraint class]]) {
            ct.active = NO;
        }
    }
}

- (void) disableCustomViewCtAll {
    NSAssert(_customViewCtArr, @"[E]%s: 关闭侧边栏dialog.customView的约束时，约束arr不能为nil！", __FUNCTION__);
    
    _customView.translatesAutoresizingMaskIntoConstraints = NO;
    
    for (NSLayoutConstraint * ct in _customViewCtArr) {
        // 注：ct不会为[NSNull null]，但为了保持书写风格统一，还是加一句判断
        if ([ct isKindOfClass:[NSLayoutConstraint class]]) {
            ct.active = NO;
        }
    }
}

- (void) enableDialogCtAfterPresented {
    NSAssert(_dialogCtDic, @"[E]%s: 开启侧边栏dialog在presented之后的约束时，约束dic不能为nil！", __FUNCTION__);
    
    _viDialog.translatesAutoresizingMaskIntoConstraints = NO;
    
    for (NSString * ctKey in [_dialogCtDic allKeys]) {
        NSLayoutConstraint * ct = [_dialogCtDic objectForKey:ctKey];
        // 注：ct可能为[NSNull null]
        if ([ct isKindOfClass:[NSLayoutConstraint class]]) {
            ct.active = YES;
        }
    }
}

- (void) enableDialogCtExceptCenter {
    NSAssert(_dialogCtDic, @"[E]%s: 开启侧边栏dialog在presented之后的约束时，约束dic不能为nil！", __FUNCTION__);
    
    _viDialog.translatesAutoresizingMaskIntoConstraints = NO;
    
    for (NSString * ctKey in [_dialogCtDic allKeys]) {
        NSLayoutConstraint * ct = [_dialogCtDic objectForKey:ctKey];
        // 注：ct可能为[NSNull null]
        if ([ct isKindOfClass:[NSLayoutConstraint class]]
            && (
                [ctKey isEqualToString:TSC_SIDEBAR_DIALOG_CT_DIC_KEY_CENTER_X] == NO
                ||
                [ctKey isEqualToString:TSC_SIDEBAR_DIALOG_CT_DIC_KEY_CENTER_Y] == NO
                )
            ) {
            ct.active = YES;
        }
    }
}

- (void) enableCustomViewCtAll {
    NSAssert(_customViewCtArr, @"[E]%s: 开启侧边栏dialog.customView的约束时，约束arr不能为nil！", __FUNCTION__);
    
    _customView.translatesAutoresizingMaskIntoConstraints = NO;
    
    for (NSLayoutConstraint * ct in _customViewCtArr) {
        // 注：ct不会为[NSNull null]，但为了保持书写风格统一，还是加一句判断
        if ([ct isKindOfClass:[NSLayoutConstraint class]]) {
            ct.active = YES;
        }
    }
}

#pragma mark delegate

- (void) viBGClicked {
    [self dismissAnimated:_bgClickedDismissAnimated completion:_bgClickedDismissCompletion];
}

@end
